package com.chenfan.magic.config;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chenfan.common.config.Constant;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.vo.Response;
import com.chenfan.common.vo.UserVO;
import com.chenfan.magic.constant.MagicConstant;
import com.chenfan.magic.constant.TokenConstant;
import com.chenfan.magic.entity.SPrivilegeButtonRes;
import com.chenfan.magic.entity.SPrivilegeRes;
import com.chenfan.magic.exception.MagicState;
import com.chenfan.magic.feign.PrivilegeServer;
import com.chenfan.magic.utils.StringUtil;
import com.chenfan.privilege.common.constant.RedisKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuming
 * @date 2021-03-22 17:12
 */
@Slf4j
@Component
@RefreshScope
public class MagicHandlerInterceptorAdapter extends HandlerInterceptorAdapter {

    private ThreadLocal<Boolean> flag = new ThreadLocal();

    @Autowired
    private PrivilegeServer privilegeServer;

    @Value(value = "${interface.white}")
    private String interfaceWhiteList;

    @Autowired
    @Qualifier("redisTokenTemplate")
    private RedisTemplate redisTokenTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader(Constant.AUTHORIZATION_TOKEN);
        String appKey = request.getHeader(TokenConstant.APP_KEY);
        //权限菜单在登录后,在[用户权限服务]中会把菜单放入缓存中
        UserVO userVO = getUserVO(request);

        flag.set(false);
        //获取当前接口url
        String currentUri = request.getRequestURI();
        String[] currentPaths = currentUri.split("/");
        //第谷接口直接跳过
        if (currentUri.contains(MagicConstant.DIGU_PATH)) {
            return false;
        }

        //当前应用接口白名单过滤
        List<String> interfaceWhites = new ArrayList();
        if (!StringUtils.isEmpty(interfaceWhiteList)) {
            String[] list = interfaceWhiteList.split(MagicConstant.COMMA);
            interfaceWhites = Arrays.asList(list);
        }
        if (interfaceWhites.contains(currentPaths[currentPaths.length - 1])) {
            return true;
        }

        StringBuilder key = new StringBuilder(RedisKey.user(userVO.getUserId()));
        key.append(":resourceList").append(":").append(appKey);
        String userResources = JSONObject.toJSONString(redisTokenTemplate.opsForValue().get(key.toString()));
        List<SPrivilegeButtonRes> privilegeRes = null;
        if (!StringUtils.isEmpty(userResources) && !MagicConstant.NULL_STR.equals(userResources) && !MagicConstant.EMPTY_ARRAY_STR.equals(userResources)) {
            privilegeRes = JSONObject.parseArray(userResources, SPrivilegeButtonRes.class);
        } else {
            Response privilegeResponse = privilegeServer.getUserResources(token, appKey);
            if (Objects.isNull(privilegeResponse) || Objects.isNull(privilegeResponse.getObj())) {
                throw new BusinessException(MagicState.NO_PRIVILEGE);
            }
            String jsonString = JSONArray.toJSONString(privilegeResponse.getObj());
            privilegeRes = JSONObject.parseArray(jsonString, SPrivilegeButtonRes.class);
        }

        if (CollectionUtils.isEmpty(privilegeRes)) {
            throw new BusinessException(MagicState.GET_PRIVILEGE_FAIL);
        }

        //获取接口的详细信息
        Response<List<SPrivilegeRes>> listResponse = privilegeServer.getListByCode(currentPaths[currentPaths.length - 1]);
        List<SPrivilegeRes> sPrivilegeRes = Optional.ofNullable(listResponse).map(x -> x.getObj()).orElse(Collections.EMPTY_LIST);
        Set<String> parentCodes = sPrivilegeRes.stream().map(x -> x.getParentCode()).collect(Collectors.toSet());

        try {
            recursion(privilegeRes, parentCodes);
        } catch (RuntimeException e) {
            log.error("preHandle method error:{}, {}", flag.get(), e);
        }

        //匹配用户没有权限,则拦截用户操作
//        if (!flag.get()) {
//            throw new BusinessException(MagicState.NO_OPERATION_PRIVILEGE);
//        }
        return super.preHandle(request, response, handler);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //移除用户信息
        UserVoConstextHolder.remove();
        flag.remove();
        super.afterCompletion(request, response, handler, ex);
    }

    /**
     * 获取用户信息
     *
     * @param request
     * @return
     */
    @Deprecated
    private UserVO getUserVO(HttpServletRequest request) {
        String token = request.getHeader(Constant.AUTHORIZATION_TOKEN);
        if (StringUtils.isEmpty(token)) {
            throw new BusinessException(Constant.UNAUTHORIZED, "用户登录信息失效");
        }
        UserVO attribute = JSONObject.parseObject(JSONObject.toJSONString(redisTokenTemplate.opsForValue().get(Constant.AUTHORIZATION + ":" + token)), UserVO.class);
        UserVoConstextHolder.setUserVo(attribute);
        return UserVoConstextHolder.getUserVo();
    }

    /**
     * 递归获取url地址
     *
     * @param childs
     */
    private void recursion(List<SPrivilegeButtonRes> childs, Set<String> parentCodes) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String currentUri = request.getRequestURI();
        for (SPrivilegeButtonRes child : childs) {
            if (!CollectionUtils.isEmpty(child.getButtons())) {
                List<SPrivilegeButtonRes.Buttons> buttons = child.getButtons();
                //如果是导出接口权限,需要判断它是否有查询按钮权限
                if (currentUri.contains(MagicConstant.EXPORT_PATH)) {
                    Optional<SPrivilegeButtonRes.Buttons> button = buttons.stream().filter(btn -> parentCodes.contains(btn.getParentCode()) || parentCodes.contains(btn.getPrivilegeCode())).findAny();
                    if (button.isPresent()) {
                        for (SPrivilegeButtonRes.Buttons btn : buttons) {
                            if (!StringUtils.isEmpty(btn.getBtnKey()) && btn.getBtnKey().contains(MagicConstant.SBTN) && btn.getStatus() && button.get().getStatus()) {
                                flag.set(true);
                                throw new RuntimeException();
                            }
                        }
                    }
                } else {
                    //查询接口权限
                    for (SPrivilegeButtonRes.Buttons btn : buttons) {
                        boolean flag = (parentCodes.contains(btn.getParentCode()) || parentCodes.contains(btn.getPrivilegeCode())) && btn.getStatus();
                        if (flag) {
                            this.flag.set(true);
                            throw new RuntimeException();
                        }
                    }
                }
            }

            if (!CollectionUtils.isEmpty(child.getChildren())) {
                List<SPrivilegeButtonRes> childList = child.getChildren();
                recursion(childList, parentCodes);
            }

        }


    }
}
